Write a custom CUDA kernel to optimize the Meta-AconC activation function logic using double precision (float64).

The mathematical definition:
f(x) = (p1 * x - p2 * x) * sigmoid(beta * (p1 * x - p2 * x)) + p2 * x

Shape Analysis:
- x: (N, C, H, W)
- p1, p2: (1, C, 1, 1). Learnable parameters shared across N, H, W.
- beta: (N, C, 1, 1). Generated dynamically per sample and per channel.

Problem Analysis:
1. Complex Broadcasting: The kernel must handle two different broadcasting patterns simultaneously. `p1`/`p2` broadcast over (N, H, W), while `beta` broadcasts over (H, W) but varies along N.
2. Memory Bound: The formula involves multiple reads/writes and generates large intermediate tensors if executed sequentially.
3. Precision: Double precision is required for stability.

Optimization Strategy: Fused Dual-Broadcasting Kernel

1. Coordinate Mapping: From the global linear index of `x`, we must extract the batch index `n` and channel index `c` to locate the correct `p1[c]` and `beta[n, c]`.
   - c = (idx / (H*W)) % C
   - n = idx / (C*H*W)

2. Fused Computation: Load `x`, `p1`, `p2`, and `beta` once, compute the result in registers using `double` arithmetic, and store.

3. Vectorized Access: Use `double2` (128-bit) for efficient memory transaction. Coordinate calculation needs to handle the vectorized unrolling carefully.
  
Here's an example to show you the syntax of inline embedding custom CUDA operators in torch: The example given architecture is:   
  
```python
import torch
import torch.nn as nn

BATCH_SIZE = 32
CHANNELS = 64
HEIGHT = 56
WIDTH = 56
SHAPE = (BATCH_SIZE, CHANNELS, HEIGHT, WIDTH)
BETA_SHAPE = (BATCH_SIZE, CHANNELS, 1, 1)

DTYPE = torch.float64

class MetaAconC(nn.Module):
    """ ACON activation (activate or not).
    # MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network
    # according to "Activate or Not: Learning Customized Activation" <https://arxiv.org/pdf/2009.04759.pdf>.
    """
    def __init__(self, p1, p2):
        super().__init__()
        self.p1 = nn.Parameter(p1)
        self.p2 = nn.Parameter(p2)

    def forward(self, x, beta):
        # p1, p2: (1, C, 1, 1) broadcast to (N, C, H, W)
        # beta:   (N, C, 1, 1) broadcast to (N, C, H, W)
        # x:      (N, C, H, W)
        d1 = self.p1 * x
        d2 = self.p2 * x
        diff = d1 - d2
        return diff * torch.sigmoid(beta * diff) + d2

class Model(nn.Module):
    def __init__(self, p1, p2):
        super(Model, self).__init__()
        self.act = MetaAconC(p1, p2)
    
    def forward(self, x: torch.Tensor, beta: torch.Tensor) -> torch.Tensor:
        return self.act(x, beta)

def get_inputs():
    x = torch.randn(SHAPE, dtype=DTYPE)
    beta = torch.randn(BETA_SHAPE, dtype=DTYPE)
    return [x.contiguous(), beta.contiguous()]

def get_init_inputs():
    p1 = torch.randn(1, CHANNELS, 1, 1, dtype=DTYPE)
    p2 = torch.randn(1, CHANNELS, 1, 1, dtype=DTYPE)
    return [p1, p2]